// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_BASIC_PACKET_HPP_
#define _XBASE_BASIC_PACKET_HPP_

#include "wrapper.hpp"

namespace xbase
{
	
#define def_packet_1(t1, packet) typedef		\
	basic_packet<t1,				\
		     basic_packet_bad_index> packet
	
#define def_packet_2(t1, t2, packet) typedef				\
	basic_packet<t2,						\
		     basic_packet<t1,					\
				  basic_packet_bad_index> > packet
	
#define def_packet_3(t1, t2, t3, packet) typedef			\
	basic_packet<t3,						\
		     basic_packet<t2,					\
				  basic_packet<t1,			\
					       basic_packet_bad_index > > > packet
	
#define def_packet_4(t1, t2, t3, t4, packet) typedef			\
	basic_packet<t4,						\
		     basic_packet<t3,					\
				  basic_packet<t2,			\
					       basic_packet<t1,		\
							    basic_packet_bad_index > > > > packet

#define def_packet_5(t1, t2, t3, t4, t5, packet) typedef		\
	basic_packet<t5,						\
		     basic_packet<t4,					\
				  basic_packet<t3,			\
					       basic_packet<t2,		\
							    basic_packet<t1, \
									 basic_packet_bad_index > > > > > packet

	struct basic_packet_bad_index {};

	template<typename T, typename BaseT>
	struct basic_packet : public BaseT
	{
		typedef BaseT base_type;
		//typedef bits::net_byte_order byteorder;
		typedef T value_type;

		enum { index = base_type::index + 1 };

		T m_value;

		// inline
		// bool load(const char *data, const char **end) {
		// 	typedef integer_wrapper<T, byteorder> wT;
		// 	const char * base_data = data;
		// 	data = *end;
		// 	const bool ret = (base_type::load(base_data, &data) // 如果成功，data将指向当前数据的起始位置
		// 			  && (*end >= (data + wT::MINIMAL_BYTES)));
		// 	if(ret)
		// 	{
		// 		const wT *p = wrapper_cast<const wT*>(data);
		// 		m_value = p->get();
		// 		*end = data + p->bytes();
		// 	}
		// 	return ret;
		// }

		// inline
		// bool save(char *data, char **end) {
		// 	typedef integer_wrapper<T, byteorder> wT;
		// 	char * base_data = data;
		// 	data = *end;
		// 	const bool ret = (base_type::save(base_data, &data) // 如果成功，data将指向当前数据的起始位置
		// 			  && (*end >= (data + wT::MINIMAL_BYTES)));
		// 	if(ret)
		// 	{
		// 		wT *p = wrapper_cast<wT*>(data);
		// 		p->set(m_value);
		// 		*end = data + p->bytes();
		// 	}
		// 	return ret;
		// }
	};

	template<typename T>
	struct basic_packet<T, basic_packet_bad_index>
	{
		typedef basic_packet_bad_index base_type;
		//typedef bits::net_byte_order byteorder;
		typedef T value_type;

		enum { index = 0 };

		T m_value;

		// inline
		// bool load(const char *data, const char **end) {
		// 	typedef integer_wrapper<T, byteorder> wT;
		// 	const bool ret = (*end >= (data + wT::MINIMAL_BYTES));
		// 	if(ret)
		// 	{
		// 		const wT *p = wrapper_cast<const wT*>(data);
		// 		m_value = p->get();
		// 		*end = data + p->bytes();
		// 	}
		// 	return ret;
		// }

		// inline
		// bool save(char *data, char **end) {
		// 	typedef integer_wrapper<T, byteorder> wT;
		// 	const bool ret = (*end >= (data + wT::MINIMAL_BYTES));
		// 	if(ret)
		// 	{
		// 		wT *p = wrapper_cast<wT*>(data);
		// 		p->set(m_value);
		// 		*end = data + p->bytes();
		// 	}
		// 	return ret;
		// }
	};

	namespace details
	{
		template<typename Packet,
			 std::size_t cur_index,
			 std::size_t index>
		struct find_packet
		{
			typedef typename Packet::base_type next_packet_type;

			typedef find_packet< next_packet_type,
					     next_packet_type::index,
					     index > find_type;
			typedef typename find_type::packet_type packet_type;
		};

		template<typename Packet,
			 std::size_t index>
		struct find_packet<Packet, index, index>
		{
			typedef Packet packet_type;
		};

		template<typename T, std::size_t index>
		struct packet_value_helper
		{
			typedef find_packet<T,
					    T::index,
					    index> find_type;
			typedef typename find_type::packet_type packet_type;
			typedef typename packet_type::value_type value_type;
		};

		template<typename Packet,
			 typename ByteOrder,
			 typename NextPacket>
		struct packet_loader
		{
			static inline
			bool load(Packet &packet, const char *data, const char **end) {
				typedef integer_wrapper<typename Packet::value_type, ByteOrder> wT;
				const char * base_data = data;
				data = *end;
				const bool ret = (packet_loader<NextPacket, ByteOrder, typename NextPacket::base_type>::load(packet, base_data, &data) // 如果成功，data将指向当前数据的起始位置
						  && (*end >= (data + wT::MINIMAL_BYTES)));
				if(ret)
				{
					const wT *p = wrapper_cast<const wT*>(data);
					packet.m_value = p->get();
					*end = data + p->bytes();
				}
				return ret;
			}
		};

		template<typename Packet,
			 typename ByteOrder>
		struct packet_loader<Packet, ByteOrder, basic_packet_bad_index>
		{
			static inline
			bool load(Packet &packet, const char *data, const char **end) {
				typedef integer_wrapper<typename Packet::value_type, ByteOrder> wT;
				const bool ret = (*end >= (data + wT::MINIMAL_BYTES));
				if(ret)
				{
					const wT *p = wrapper_cast<const wT*>(data);
					packet.m_value = p->get();
					*end = data + p->bytes();
				}
				return ret;
			}
		};

		template<typename Packet,
			 typename ByteOrder,
			 typename NextPacket>
		struct packet_saver
		{
			static inline
			bool save(Packet &packet, char *data, char **end) {
				typedef integer_wrapper<typename Packet::value_type, ByteOrder> wT;
				char * base_data = data;
				data = *end;
				const bool ret = (packet_saver<NextPacket, ByteOrder, typename NextPacket::base_type>::save(packet, base_data, &data) // 如果成功，data将指向当前数据的起始位置
						  && (*end >= (data + wT::MINIMAL_BYTES)));
				if(ret)
				{
					wT *p = wrapper_cast<wT*>(data);
					p->set(packet.m_value);
					*end = data + p->bytes();
				}
				return ret;
			}
		};

		template<typename Packet,
			 typename ByteOrder>
		struct packet_saver<Packet, ByteOrder, basic_packet_bad_index>
		{
			static inline
			bool save(Packet &packet, char *data, char **end) {
				typedef integer_wrapper<typename Packet::value_type, ByteOrder> wT;
				const bool ret = (*end >= (data + wT::MINIMAL_BYTES));
				if(ret)
				{
					wT *p = wrapper_cast<wT*>(data);
					p->set(packet.m_value);
					*end = data + p->bytes();
				}
				return ret;
			}
		};
		
	} // namespace details

	template<std::size_t index, typename Packet>
	inline
	typename details::packet_value_helper<Packet, index>::value_type &
	packet_value(Packet &packet)
	{
		typedef typename details::packet_value_helper<Packet, index>::packet_type packet_type;
		return dynamic_cast<packet_type&>(packet).m_value;
	}

	template<typename Packet, typename ByteOrder>
	struct basic_packet_istream
	{
		typedef Packet packet_type;
		typedef ByteOrder byteorder;

		enum status {
			s_ok = 0,
			s_error_not_enough
		};

		const char *m_data;
		const char *m_pos;
		const char *m_end;
		status m_status;

		basic_packet_istream(const char *data, std::size_t size)
			: m_data(data)
			, m_pos(data)
			, m_end(data + size)
			, m_status(s_ok) {}

		inline
		basic_packet_istream<packet_type, byteorder> &operator>> (Packet &packet) {
			if(good())
			{
				const char * end = m_end;
				const bool ret = details::packet_loader<packet_type, byteorder, typename packet_type::base_type>::load(packet, m_pos, &end);
				m_pos = end; // update pos
				if(! ret)
				{
					m_status = s_error_not_enough;
				}
			}
			return *this;
		}

		bool good() {
			return m_status == s_ok;
		}

		std::size_t loaded_size() {
			return m_pos - m_data;
		}

		std::size_t left_size() {
			return m_end - m_pos;
		}
	};

	template<typename Packet, typename ByteOrder>
	struct basic_packet_ostream
	{
		typedef Packet packet_type;
		typedef ByteOrder byteorder;

		enum status {
			s_ok = 0,
			s_error_not_enough
		};

		char *m_data;
		char *m_pos;
		char *m_end;
		status m_status;

		basic_packet_ostream(char *data, std::size_t size)
			: m_data(data)
			, m_pos(data)
			, m_end(data + size)
			, m_status(s_ok) {}

		inline
		basic_packet_ostream<packet_type, byteorder> &operator<< (Packet &packet) {
			if(good())
			{
				char * end = m_end;
				const bool ret = details::packet_saver<packet_type, byteorder, typename packet_type::base_type>::save(packet, m_pos, &end);
				m_pos = end; // update pos
				if(! ret)
				{
					m_status = s_error_not_enough;
				}
			}
			return *this;
		}

		bool good() {
			return m_status == s_ok;
		}

		std::size_t saved_size() {
			return m_pos - m_data;
		}

		std::size_t left_size() {
			return m_end - m_pos;
		}
	};

} // namespace xbase

#endif	// _XBASE_BASIC_PACKET_HPP_
